/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.openbookformat.defaultparser;


import com.smallutil.common.TextUtil;
import org.openbookformat.core.OBFParser;
import org.openbookformat.tags.CompositeTag;
import org.openbookformat.tags.FnMarkTag;
import org.openbookformat.tags.FnTextTag;
import org.openbookformat.tags.FootnoteTag;
import org.openbookformat.tags.FormatTag;
import org.openbookformat.tags.HeadingTag;
import org.openbookformat.tags.MboxTag;
import org.openbookformat.tags.PagebreakTag;
import org.openbookformat.tags.ParTag;
import org.openbookformat.tags.PoetTag;
import org.openbookformat.tags.RhymeTag;
import org.openbookformat.tags.Tag;
import org.openbookformat.tags.Tag.Align;
import org.openbookformat.tags.TagNotFoundException;
import org.openbookformat.tags.Text;
import org.openbookformat.tags.WidthAttr;
import org.openide.util.lookup.ServiceProvider;

/**
 *
 * @author MUFEED
 */

@ServiceProvider(service=OBFParser.class)
public class OldOBFDefaultParser implements OBFParser {
    CompositeTag tags;
    

    public OldOBFDefaultParser() {
        tags = new CompositeTag();
    }

    @Override
    public Tag parse(String obf_text) throws TagNotFoundException {
        //Clearing the buffer and the tags.
        tags.clearTags();

        //Convert text to an array of strings; each element is a tag.
        String tmp = obf_text.replace("<", "\n<");
        tmp = tmp.replace(">", ">\n");
        tmp = TextUtil.removeBlankLines(tmp);
        String[] lines = tmp.split("\n");

        parseTags(lines, tags);
        return tags;
    }



    private void parseTags(String[] lines, CompositeTag sTag) throws TagNotFoundException {
        parseTags(lines, 0, lines.length-1, sTag);
    }

    private void parseTags(String[] lines, int start, int end, CompositeTag sTag) throws TagNotFoundException {
        for (int i = start; i < end +1; i++) {
            //System.out.println("i:\t" + i  + "\t" + lines[i]);
            if (lines[i].trim().startsWith("<")) {
                if (lines[i].indexOf("/>") != -1) {
                    //Single Tag
                    sTag.addTag(convertTag(new String[]{lines[i]}));
                } else {
                    String tag = null;
                    int n, m, k;

                    n = lines[i].indexOf(">");
                    m = lines[i].indexOf(" ");
                    k = i;
                    if( m == -1) {
                        tag = lines[i].substring(1, n);
                    } else {
                        tag = lines[i].substring(1, Math.min(n, m));
                    }

                    while(!lines[++i].matches("<\\s?/\\s?" + tag + "\\s?>")) {
                    }

                    sTag.addTag(convertTag(lines, k, i, TagType.valueOf(tag.toUpperCase())));
                }
            } else {
                //pure text
                sTag.addTag(new Text(lines[i]));
                //System.out.println("Text:\t" + lines[i]);
            }
        }
    }

    public final static int PAR_TAG         = 001;
    public final static int PAGEBREAK_TAG   = 002;
    public final static int MBOX_TAG        = 003;
    public final static int HEADING_TAG     = 004;

    public enum TagType {
        BF,
        COMPOSITE,
        HEADING,
        FORMAT,
        FN_TEXT,
        FN,
        FN_MARK,
        MBOX,
        PAR,
        PAGEBREAK,
        POET,
        RHYME,
        TEXT,
        TOC_TEXT,
        SUPER_SCRIPT,
        SUB_SCRIPT,
        VERSE;

        public TagType getTagType(Tag tag) {
            if (tag instanceof Text)
                return TagType.TEXT;
            if (tag instanceof FnMarkTag)
                return TagType.FN_MARK;
            if (tag instanceof FootnoteTag)
                return TagType.FN_TEXT;
            if (tag instanceof PagebreakTag)
                return TagType.PAGEBREAK;


           return TagType.valueOf(tag.getClass().getSimpleName().substring(
                    0, tag.getClass().getSimpleName().indexOf("Tag")).toUpperCase());
        }
    }

    public Tag convertTag(String[] lines) throws TagNotFoundException {
        return convertTag(lines, 0, lines.length -1);
    }

    public Tag convertTag(String[] lines, int start, int end) throws TagNotFoundException {
        String tag = null;
        int n, m;
        if (start == end) {
           //Single Tag
           //System.out.println("lines[0]:" + lines[0]);
           //tag = lines[start].substring(1, lines[start].lastIndexOf("/"));
           n = lines[start].indexOf("/");
           m = lines[start].indexOf(" ");
           // Multi Tag
           if( m == -1) {
               tag = lines[start].substring(1, n);
           } else {
               tag = lines[start].substring(1, Math.min(n, m));
           }

           //System.out.println("sTag:\t" + tag);
        } else {

           n = lines[start].indexOf(">");
           m = lines[start].indexOf(" ");
           // Multi Tag
           if( m == -1) {
               tag = lines[start].substring(1, n);
           } else {
               tag = lines[start].substring(1, Math.min(n, m));
           }
           //System.out.println("mTag:\t" + tag);
        }
        //System.out.println("TTTAAAGGG:\t" + lines[start]);
        try{
            TagType.valueOf(tag.toUpperCase());
        } catch(IllegalArgumentException ex) {
            throw new TagNotFoundException("[" +  tag + "] tag was not found.");
        }
        return convertTag(lines, start, end, TagType.valueOf(tag.toUpperCase()));
    }

    public Tag convertTag(String[] lines, int start, int end, TagType type) throws TagNotFoundException {
        System.out.println("Convert Tag [Type:" + type + ", start:" + start + ", end:" + end + "]" );
        Tag tag;
        CompositeTag cTag = null;
        String mark;
        switch(type) {
            case BF:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return cTag;
            case FORMAT:
                String style = getAttr(lines[0], "style");
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return new FormatTag(style, cTag);
            case HEADING:
                int level = Integer.parseInt(getAttr(lines[start], "level"));
                boolean inTOC = getAttr(lines[start], "intoc").equals("0")?false: true;
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return new HeadingTag(level, inTOC, (CompositeTag) cTag.getTag(0),
                        (CompositeTag) cTag.getTag(1));
            case FN_TEXT:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                tag = (Tag) new FootnoteTag();
                for(int i = 0; i < cTag.size(); i++)
                        ((FootnoteTag) tag).addFnTextTag((FnTextTag)cTag.getTag(i));
                return tag;
            case FN:
                mark = getAttr(lines[start], "mark");
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return new FnTextTag(mark, cTag);
            case FN_MARK:
                mark = getAttr(lines[start], "mark");
                return new FnMarkTag(mark);
            case MBOX:
                Align align = Align.valueOf(
                        getAttr(lines[start], "align").toUpperCase());
                WidthAttr width = WidthAttr.parseWidthAttr(
                        getAttr(lines[start], "width"));
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return new MboxTag(align, width, cTag);
            case PAGEBREAK:
                int pageNumber = Integer.parseInt(getAttr(lines[start], "n"));
                String alpha = getAttr(lines[start], "alpha");
                if(alpha == null) {
                    return new PagebreakTag(pageNumber);
                } else {
                    return new PagebreakTag(pageNumber, alpha.equals("1"));
                }
                case PAR:
                tag = new ParTag();
                return tag;
            case POET:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                tag = (Tag) new PoetTag();
                for(int i = 0; i < cTag.size(); i++)
                    ((PoetTag) tag).addRhyme((RhymeTag) cTag.getTag(i));
                return tag;
            case RHYME:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                tag = new RhymeTag();
                for(int i = 0; i < cTag.size(); i++)
                    ((RhymeTag) tag).addVerse((CompositeTag) cTag.getTag(i));
                return tag;
            case SUB_SCRIPT:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return cTag;
            case SUPER_SCRIPT:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return cTag;
            case TEXT:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return cTag;
            case TOC_TEXT:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return cTag;
            case VERSE:
                cTag = new CompositeTag();
                parseTags(lines, start+1, end-1, cTag);
                return cTag;

        }
        return null;
    }
    
    public String getAttr(String tag, String attr) {
        //System.out.println("tag: " + tag + ", attr: " + attr);
        int i = tag.indexOf(attr);
        if (i == -1)
            return null;
        int j, k;
        j = tag.indexOf("'", i);
        k = tag.indexOf("'", j+1);
        return tag.substring(j+1, k);
    }


}
